#ifndef __SIMPLECORE_H__
#define __SIMPLECORE_H__

#include <cstdlib>
#include "GAcore.hpp"
#include "popolazione.hpp"
#include "common.hpp"


/** \class SimpleCoreException
 *  \brief Eccezioni lanciate dalla classe SimpleCore
 */
class SimpleCoreException : public GAcoreException
{
    public:
    SimpleCoreException(char *mess) : GAcoreException(mess) {};
};

/** \class SimpleCore
 *  \brief Implementa un schema standard di selezione-mutazione-crossover
 */
class SimpleCore : public GAcore
{
public:
    //! Puntatore alla popolazione principale
    Popolazione *M;

    //! Puntatore alla popolazione di supporto
    Popolazione *N;
protected:
    //! Probabilita' di crossover
    float pc;
    //! Probabilita' di mutazione
    float pm;
    //! Numero minimo di bit modificati per mutazione
    int min_rate;
    //! Numero massimo di bit modificati per mutazione
    int max_rate;
    //! Dimensione del torneo
    unsigned int t_size;
    //! Probabilita' di vittoria del migliore del torneo
    float pt;
    //!Numero di individui che vengono re-inizializzati ad ogni generazione
    unsigned int random_ind;

    //! Statistiche
    float numCrossover;  //!< Numero di crossover medio sul numero di generazioni eseguite
    float numMut;        //!< Numero medio di bit mutati per individuo

    public:

    //! Parametri calcolabili
    enum params {
        PARAM_ALL           = 0xFFFFFFFF,       //!< Calcola tutti i parametri
        PARAM_HAM_BEST      = 0x00000020,       //!< Calcola distanza di hamming dall'individuo migliore
        PARAM_N_CROSS       = 0x00000010,       //!< Calcola il numero di crossover (per generazione) nell'ultima chiamata a \c run_generation
        PARAM_N_MUT         = 0x00000008,       //!< Calcola il numero di mutazioni per individuo (per generazione) nell'ultima chiamata a \c run_generation
        PARAM_VAR_SCORE     = 0x00000004,       //!< Varianza del valore di fitness su tutta la popolazione
        PARAM_MEAN_SCORE    = 0x00000002,       //!< Fitness medio
        PARAM_BEST_SCORE    = 0x00000001        //!< Best score
    };

    /** Costruttore standard. Inizializza il core e carica le configurazioni
     *
     *  \param[in]  val         Valutatore da utilizzare.
     *  \param[in]  settings    Contiene i dati di configurazione del core.
     */
    SimpleCore(Validator *val,GAmodSettings &settings) throw(SimpleCoreException);

    /**
     *  I settings di configurazione da fornire sono:
     *  \arg \c pop_size:   specifica la dimensione della popolazione (puo' non essere specificata in caso si legga da file)
     *  \arg \c pop_file:   file dal quale leggere la popolazione
     *  \arg \c pt:         probabilita' di vittoria dell'individuo migliore del torneo
     *  \arg \c pm:         probabilita' di mutazione
     *  \arg \c pc:         probabilita' di crossover
     *  \arg \c t_size:     dimensione del torneo
     *  \arg \c min_rate:   rate minimo di mutazione
     *  \arg \c max_rate:   rate massimo di mutazione
     *
     *  \param[in]  settings    Contiene i dati di configurazione
     *  \param[in]  le          Specifica il comportamento a fronte della mancata specifica di un parametro
     *
     *  \return                 Numero di parametri letti
     */
    int loadSettings(GAmodSettings &settings,load_exc le = GAcore::THROW_EXCEPTION) throw(SimpleCoreException);

    /** Restituisce informazioni sull'evoluzione
     *
     *  \param[out] settings    Contenitore delle statistiche calcolate
     *  \param[in] lista       Lista dei parametri da calcolare
     *  \return                 Numero di statistiche calcolate
     */
    int getGenerationData(GAmodSettings &settings,HERAuint32 lista = 0);

    /** Esegue l'evoluzione per il numero di generazioni specificato
     *
     *  \param[in]  num Numero di generazioni da eseguire
     *  \return         Numero di generazioni eseguite
     */
    int runGeneration(int num);

    void getPopolazione(Popolazione &p){p = (*M);};
};

#endif
